package cn.rocksolid.sport.common.utils;

import cn.rocksolid.sport.common.Constant.Symbol;
import org.apache.commons.lang3.ArrayUtils;

import java.util.UUID;

public class Guid {
  private static final Character[] URL_BASE64_DIGITS =
          ArrayUtils.toObject("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray());
  private static final long HI_MASK = (1L << 6) - 1;
  private static final long LAST_HI_MASK = (1L << 4) - 1;

  private Guid() {

  }

  public static String random() {
    return UUID.randomUUID().toString().replace(Symbol.DASH, Symbol.EMPTY);
  }

  public static String shorter() {
    UUID uuid = UUID.randomUUID();
    return longToBase64(uuid.getMostSignificantBits()) + longToBase64(uuid.getLeastSignificantBits());
  }

  private static String longToBase64(long bits) {
    StringBuilder sb = new StringBuilder();
    for (int i = 58; i > -3; i -= 6) {
      if (i == -2) {
        sb.append(URL_BASE64_DIGITS[(int) ((bits >> 4) & LAST_HI_MASK)]);
      } else {
        sb.append(URL_BASE64_DIGITS[(int) ((bits >> i) & HI_MASK - 1)]);
      }
    }
    return sb.toString();
  }

  // 以下作为参考代码，后续在此基础上完成10进制转64进制的方法。
  static final char [] DigitTens = {
          '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
          '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
          '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
          '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
          '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
          '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
          '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
          '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
          '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
          '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
  } ;

  static final char [] DigitOnes = {
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  } ;

  /**
   * All possible chars for representing a number as a String
   */
  static final char[] digits = {
          '0' , '1' , '2' , '3' , '4' , '5' ,
          '6' , '7' , '8' , '9' , 'a' , 'b' ,
          'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
          'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
          'o' , 'p' , 'q' , 'r' , 's' , 't' ,
          'u' , 'v' , 'w' , 'x' , 'y' , 'z'
  };

  static int stringSize(long x) {
    long p = 10;
    for (int i = 1; i < 19; i++) {
      if (x < p) {
        return i;
      }
      p = 10 * p;
    }
    return 19;
  }

  static void getChars(long i, int index, char[] buf) {
    long q;
    int r;
    int charPos = index;
    char sign = 0;

    if (i < 0) {
      sign = '-';
      i = -i;
    }

    // Get 2 digits/iteration using longs until quotient fits into an int
    while (i > Integer.MAX_VALUE) {
      q = i / 100;
      // really: r = i - (q * 100);
      r = (int) (i - ((q << 6) + (q << 5) + (q << 2)));
      i = q;
      buf[--charPos] = DigitOnes[r];
      buf[--charPos] = DigitTens[r];
    }

    // Get 2 digits/iteration using ints
    int q2;
    int i2 = (int) i;
    while (i2 >= 65536) {
      q2 = i2 / 100;
      // really: r = i2 - (q * 100);
      r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
      i2 = q2;
      buf[--charPos] = DigitOnes[r];
      buf[--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i2 <= 65536, i2);
    for (; ; ) {
      q2 = (i2 * 52429) >>> (16 + 3);
      r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
      buf[--charPos] = digits[r];
      i2 = q2;
      if (i2 == 0) {
        break;
      }
    }
    if (sign != 0) {
      buf[--charPos] = sign;
    }
  }
}
